package cn.fang2chen.java.distributed.lock.framework.impl;

import cn.fang2chen.java.distributed.lock.framework.AbstractDistributedQueuedSynchronizer;
import cn.fang2chen.java.distributed.lock.framework.DistLockCopyAble;
import cn.fang2chen.java.distributed.lock.framework.RemoteLockParam;
import cn.fang2chen.java.distributed.lock.framework.RemoteLockSynchronizer;

/**
 * 分布式
 * 唯一 Token 租赁
 *
 * @author dcmini chen
 * @since 1.0.0
 */
public class DistributedTokenLeasing implements DistLockCopyAble {

    private final String operatorId;

    private final Sync sync;

    private final RemoteLockSynchronizer remoteLockSynchronizer;

    public DistributedTokenLeasing(final String operatorId, final RemoteLockSynchronizer remoteLockSynchronizer) {
        this.operatorId = operatorId;
        this.remoteLockSynchronizer = remoteLockSynchronizer;
        this.sync = new Sync(this.remoteLockSynchronizer);
    }

    /**
     * 尝试获取 token
     *
     * @param itemName 租赁物品
     * @param leaseTermMilli 租期
     * @return {@code true}  租借成功
     *         {@code false} 租借失败
     */
    public boolean tryGainToken(String itemName, long leaseTermMilli) {
        return sync.tryAcquireDistributed(1, new RemoteLockParam(itemName, operatorId, leaseTermMilli));
    }

    /**
     * 归还token
     *
     * @param tokenName 物品
     * @return {@code true}  归还成功
     *         {@code false} 归还失败
     */
    public boolean returnToken(String tokenName) {
        return sync.releaseDistributed(1, new RemoteLockParam(tokenName, operatorId, 1));
    }

    /**
     * 查看剩余租期
     *
     * @param tokenName 物品
     * @return 剩余租期
     */
    public long remainingLeaseTerm(String tokenName) {
        return sync.remainingTime(new RemoteLockParam(tokenName, operatorId, 1));
    }

    @Override
    public Object copy(RemoteLockParam remoteLockParam) {
        return new DistributedTokenLeasing(remoteLockParam.getOperatorId(), remoteLockSynchronizer);
    }

    /**
     * 和 {@link DistributedMutex} 的  Sync 实现相同
     */
    private static class Sync extends AbstractDistributedQueuedSynchronizer {

        private final RemoteLockSynchronizer remoteLockSynchronizer;

        public Sync(final RemoteLockSynchronizer remoteLockSynchronizer) {
            this.remoteLockSynchronizer = remoteLockSynchronizer;
        }

        @Override
        protected RemoteLockSynchronizer remoteLockSynchronizer() {
            return this.remoteLockSynchronizer;
        }

        @Override
        public boolean tryAcquireDistributed(int arg, RemoteLockParam remoteLockParam) {
            return remoteLockSynchronizer().tryAcquire(remoteLockParam);
        }

        @Override
        public boolean releaseDistributed(int arg, RemoteLockParam remoteLockParam) {
            return remoteLockRelease(remoteLockParam);
        }
    }
    
}
